#include<stdio.h>
#include<stdlib.h>
#include<string.h> // memset 
#include<time.h>
#include<string>
#include<iostream>
#include <memory>


#include<sys/types.h> //使用网络包含的库
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>  
#include<thread>

#include "include/BIOServer.h"

using namespace std;

/*
netstat -anp -tulpn 
*/

// 线程处理函数，必须符合 HTaskFunc 类型
void* do_work( unique_ptr<HTASK_Param>& param ){      
    int cfd =  * (param->cfd);  
    char* buf2 = param->buf2.get();
    int n; // 读取数据长度
     
    // 读数据
    // printf("正在等待数据, fd=[%d]\n", cfd); 
    n = read(cfd, buf2, MAXBODY);
    if(n <= 0)
    {
        printf("read error or [%d] client close\n", cfd);
        return (void*)0;
    }  
    printf("recv: n=%d\n", n); 
    // 解包
    HqHttpHead head(buf2, n);
    // cout << head << endl;  // 查看请求头

    HqHttpResHead res; 
    auto it=ALL_VIEW.find(head.path );
    if( it != ALL_VIEW.end() ){
        // 1 调用自定义的函数
        HViewF pfunc = it->second;
        pfunc(head, res, buf2); 
    }else{ 
        // 2 否则按照静态文件处理
        handle_static_file(head, res,  buf2 ); 
    }   

    if( ! res.mfs ){ 
        int AllLen = res.getAllData(buf2); // 把 返回头 放入buf 
        //send数据  
        // printf("%s\n", buf);  
        write(cfd, buf2, AllLen); // head + body
    }else{ 
        int headLen = res.getAllData(buf2); // 把 返回头 放入buf 
        write(cfd, buf2, headLen); // head  
        int len; 
        while( (len=res.mfs->getnext(100000)) ){
            write(cfd, buf2, len); // body
            printf(">> %d, %d,%d,%d \n", cfd, len, res.mfs->offset , res.mfs->size );
        } 
        // 自动 ~HqHttpResHead
    } 
    close(cfd);
    printf("该请求处理完毕:connfd=%d\n", cfd);
    return (void*)0;
}
 


BIOServer::BIOServer(std::string host, int port, int Thread_NUM )
{
        this->host = host;
        this->port = port;
        init_mimetype(); // 初始化 返回类型
        // 初始化路由
        initViewFunction ();
        // 线程池，固定 Thread_NUM 个
        mypool  = make_unique< Thread_pool<Thread_Task, HTask_Func, HTASK_Param>   >( Thread_NUM );
}

    
int BIOServer::startBIOServer()
{  
    srand(time(0));
    // 1创建套接字socket
    int lfd = socket(AF_INET, SOCK_STREAM, 0) ; 
    int on=1;
    setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); // 允许already use
    if(lfd < 0)
    {
        perror("soket error");
        return -1;
    }
    set_SIGPIPEN_NULL(); // 防止中断SIGPIPE后被强制退出

    struct sockaddr_in serv; // 2服务器地址
    // bzero(&serv, sizeof(serv)); //该函数初始化serv
    memset( &serv, 0, sizeof(serv) );
    serv.sin_family = AF_INET;
    serv.sin_port = htons( this->port );
    serv.sin_addr.s_addr = inet_addr(this->host.c_str());  //表示使用本地任意可用IP地址
    // 3开始绑定
    int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret < 0)
    {
        perror("bind error");
        return -1;
    }
    // 4 监听
    printf("服务器启动成功， 正在监听【%d】, \n", this->port); 
    listen(lfd, Max_Listen_num); 
    
    while(1)
    {   
        sockaddr cliaddr ;
        socklen_t addrlen = sizeof(cliaddr) ;
        // 5 接受链接
        int cfd = accept(lfd, &cliaddr, &addrlen);
        if(cfd < 0){
            printf("client accept error! \n");
            continue;
        }
        printf("get a new connection: lfd==[%d], cfd==[%d]\n", lfd, cfd);
        printf("addrlen: %d, addr: ", addrlen); // 16
        struct sockaddr_in* addr_in = (struct sockaddr_in*)(&cliaddr);
        char *s = inet_ntoa( addr_in->sin_addr ); // 192.168.130.1
        printf("IP address: %s, port:%d \n", s, addr_in->sin_port);  


        /* 1.1 linx 线程池 */  
        unique_ptr<HTASK_Param> param=make_unique<HTASK_Param>(cfd); 
        
        mypool->pool_add_work (do_work ,  param );  
    
    }
    printf("主线程退出！");   
    //关闭监听文件描述符和通信文件描述符
    close(lfd);
    printf("关闭监听文件描述符和通信文件描述符: %d\n", lfd);
    return 0;
}

void testBIOServer(){
    // 监听地址，端口，线程数量
    BIOServer server("0.0.0.0", 8000, 8);
    server.startBIOServer();

}